<template>
  <div class="ht-matrix" id="fullScreen">
    <button-screen :show.sync="isFullScreen" @screen="handleFullScreen" />
    <button-sidebar :data="sidemenus" @switch="handleSwitch" />
    <div class="ht-matrix__view" id="container1"></div>
    <div v-if="loading" class="ht-matrix__mask">
      <div class="ht-matrix__mask-card">
        <span class="ht-matrix__mask-icon">
          <em>{{ loadIcon }}</em>
          <i></i>
        </span>
        <span class="ht-matrix__mask-text">{{ loadText }}...</span>
      </div>
    </div>
  </div>
</template>

<script>
import * as THREE from 'three';
import HtMatrix from '@/components/ht-matrix/utils/matrix';
import ButtonScreen from '@components/ht-matrix/components/ButtonScreen';
import ButtonSidebar from '@components/ht-matrix/components/ButtonSidebar';
import { createObject } from '@components/ht-matrix/utils/utils';

export default {
  components: { ButtonScreen, ButtonSidebar },
  props: {
    data: {
      type: Array,
      default: () => [],
    },
    mapping: {
      type: Array,
      default: () => [],
    },
    ignored: {
      type: Array,
      default: () => [
        'identify',
        '三车间墙体001',
        '三车间地面001',
        '内部设备',
        '前道',
        '定型',
        '染色',
        '后道整装',
        'Circle1732',
      ],
    },
    coverLayer: {
      type: Array,
      default: () => [
        'Cube030_5',
        'Cube030_4',
        'Cube030_3',
        'Cube030_2',
        'Cube030_1',
        'gq001',
        'gq',
        'Cube030',
        'tree_low',
      ],
    },
  },
  data() {
    return {
      model: null,
      house: null,
      factory: null,
      factory1: null,
      bubble: {
        font: {
          size: 16,
          color: '#ffc107',
          weight: 'bold',
          family: 'Arial',
          lineHeight: 28,
        },
        pane: {
          radius: 8,
          padding: 12,
          triangle: 9,
          borderWidth: 2,
          borderColor: '#bc8f00',
          backgroundColor: '#8b8673',
        },
        prop: 'key',
        scale: 2, // 绘制图片放大倍数
        showScale: 0.5, // 0-1
      },
      locate: require('@assets/locate.png'),
      options: {
        url: '/static/model/model.gltf',
        draco: '/static/draco/',
        scale: [1, 1, 1],
        children: [],
        camera: { x: -300, y: 300, z: 450 },
      },
      matrix: null,
      loading: true,
      keyFull: false,
      loadIcon: '0%',
      loadText: '加载中',
      isFullScreen: false,
      outlook: [
        { name: 'all', x: 0, y: 120, z: 120 },
        { name: '内部设备', x: 0, y: 80, z: 80 },
        { name: '#磨毛机$', x: 0, y: 10, z: 20 },
        { name: '#精炼机$', x: 0, y: 18, z: 30 },
        { name: '#丝光机$', x: 0, y: 28, z: 30 },
        { name: '#丝光机-1#水箱温度001', x: 0, y: 20, z: 20 },
        { name: '#丝光机-2#水箱温度001', x: 0, y: 20, z: 20 },
        { name: '#丝光机-3#水箱温度001', x: 0, y: 20, z: 20 },
        { name: '#丝光机-水箱PH值001', x: 0, y: 20, z: 20 },
        { name: '#退煮机$', x: 0, y: 28, z: 29 },
        { name: '#酶退机$', x: 0, y: 20, z: 26 },
        { name: '#平蒸机$', x: 0, y: 20, z: 26 },
        { name: '#烘干机$', x: 0, y: 18, z: 24 },
        { name: '#定型机$', x: 0, y: 24, z: 24 },
        { name: '#烧毛机$', x: 0, y: 16, z: 22 },
        { name: '#轧光机$', x: 0, y: 16, z: 22 },
        { name: '#预缩机$', x: 0, y: 16, z: 22 },
        { name: '#罐蒸机$', x: 0, y: 16, z: 22 },
        { name: '#冷堆机$', x: -24, y: 24, z: 0 },
        { name: '(^[1-2]*[0-9]|^3[0-1])#染缸', x: 0, y: 20, z: 22 },
        { name: '前道|定型|染色|后道整装', x: 0, y: 40, z: 40 },
      ],
      sidemenus: [
        { label: '总览' },
        { label: '内部设备', value: [70.518964, 1.026323, -34.232994] },
        { label: '前道', value: [49.749882, 1, -28] },
        { label: '定型', value: [94.751518, 1.026323, -61.029388] },
        { label: '染色', value: [50.118786, 1.0263229, -56.905033] },
        { label: '后道整装', value: [96, 1, -35] },
      ],
    };
  },
  watch: {
    data() {
      this.handleUpdateLabel();
    },
  },
  mounted() {
    this.init();
  },
  beforeDestroy() {
    this.matrix.clear(); // 清理模型
  },
  methods: {
    init() {
      const { options } = this;
      this.matrix = new HtMatrix('container1', options);
      this.handleProgress();
      this.handleRenderer();
      this.handleDblclick();
      this.handleMousemove();
      document.addEventListener('keydown', event => (event.key === 'F11' ? (this.keyFull = true) : null));
    },

    // 获取点增量
    getPoint(name) {
      const { outlook } = this;
      return outlook.find(item => new RegExp(item.name).test(name)) || null;
    },

    // 创建位置
    createLocate() {
      const textureLoader = new THREE.TextureLoader();
      textureLoader.load(this.locate, texture => {
        const material = new THREE.SpriteMaterial({ map: texture });
        const spriteAdr = new THREE.Sprite(material);
        spriteAdr.position.set(0, 0, 80);
        this.matrix.addObject(spriteAdr);
      });
    },

    // 切换视口
    handleSwitch(valid) {
      const { matrix } = this;
      const point = this.getPoint(valid);
      matrix.visibleAllObject(obj => obj.type === 'Mesh' && !['三车间墙体', 'identify'].includes(obj.name));

      if (valid === '总览') {
        matrix.addObject(this.house);
        matrix.addObject(this.factory);
        matrix.addObject(this.factory1);
        matrix.resetScene();
      } else {
        matrix.switchSceneByName(valid, point);
        matrix.removeObjectByName('Empty');
        matrix.removeObjectByName('厂房');
        matrix.removeObjectByName('厂房001');
      }
    },

    // 加载模型
    handleProgress() {
      const { matrix } = this;
      matrix.addEventListener('progress', ({ detail }) => {
        const { loaded, total } = detail;
        if (loaded === total) this.loadText = '渲染中';
        this.loadIcon = Math.ceil((loaded / total) * 100) + '%';
      });
    },

    // 渲染模型
    handleRenderer() {
      const { matrix } = this;
      const { mapping, sidemenus } = this;
      matrix.addEventListener('renderer', () => {
        this.loading = false;
        this.house = matrix.getObjectByName('Empty');
        this.factory = matrix.getObjectByName('厂房');
        this.factory1 = matrix.getObjectByName('厂房001');
        matrix.addUserData(mapping);
        sidemenus.forEach(item => {
          if (item.value) {
            const model = createObject(item.label, item.value);
            matrix.addObject(model);
          }
        });
      });
    },

    // 点击模型
    handleDblclick() {
      let point = {};
      const { data, matrix, bubble, getPoint, ignored, coverLayer } = this;
      matrix.addEventListener('click', ({ detail }) => {
        if (!detail.name) return;
        if (ignored.includes(detail.name) || coverLayer.includes(detail.name)) return;
        if (detail.name === 'Plane029') {
          point = getPoint('内部设备');
          matrix.switchSceneByName('内部设备', point);
          matrix.removeObjectByName('Empty');
          matrix.removeObjectByName('厂房');
          matrix.removeObjectByName('厂房001');
        } else {
          point = getPoint(detail.name);
          matrix.addOutlinePass(detail);
          matrix.switchSceneByObject(detail, point);
          matrix.visibleActiveObject(detail);
          const current = data.find(
            item => item.machineName === detail.name || item.machineName === detail.name.split('-')[0]
          );
          if (current && detail.userData.data) {
            matrix.createLabelsSprite(current, detail, bubble);
          }
          this.model = detail;
          this.$emit('dbclick', current);
        }
      });
    },

    // 鼠标移动选择模型
    handleMousemove() {
      const { matrix, ignored, coverLayer } = this;
      matrix.addEventListener('mousemove', ({ detail }) => {
        if (!detail.name) return;
        if (ignored.includes(detail.name) || coverLayer.includes(detail.name)) {
          matrix.addOutlinePass(null);
          const aims = matrix.getObjectByName('Plane029');
          if (aims) {
            aims.material.transparent = false;
            aims.material.opacity = 1;
          }
        } else {
          if (detail.name === 'Plane029') {
            detail.material.transparent = true;
            detail.material.opacity = 0.3;
            matrix.outlinePass.edgeStrength = 6;
            matrix.outlinePass.edgeThickness = 2;
            matrix.outlinePass.visibleEdgeColor.set('#0a92e2');
            matrix.outlinePass.hiddenEdgeColor.set('#0a92e2');
          } else {
            matrix.outlinePass.edgeStrength = 3;
            matrix.outlinePass.edgeThickness = 1;
            matrix.outlinePass.visibleEdgeColor.set('#fd0000');
            matrix.outlinePass.hiddenEdgeColor.set('#fd0000');
          }
          matrix.addOutlinePass(detail);
        }
      });
    },

    // 全屏展示
    handleFullScreen() {
      const { isFullScreen } = this;
      const element = document.getElementById('fullScreen');
      if (isFullScreen) {
        document.exitFullscreen().then(() => {
          const isFull = window.screen.height === window.innerHeight;
          isFull ? this.matrix.resizeHandler() : null;
          this.isFullScreen = false;
        });
      } else {
        const isFull = window.screen.height === window.innerHeight;
        element.requestFullscreen().then(() => {
          isFull ? this.matrix.resizeHandler() : null;
          this.isFullScreen = true;
        });
      }
    },

    // 更新内容
    handleUpdateLabel() {
      const { data, model, matrix, bubble } = this;
      const current = data.find(
        item => item.machineName === model.name || item.machineName === model.name.split('-')[0]
      );
      if (current && model.userData.data) {
        matrix.createLabelsSprite(current, model, bubble);
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.ht-matrix {
  height: 100%;
  position: relative;
  background-color: #b7bad4;

  &__view {
    width: 100%;
    height: 100%;
    overflow: hidden;

    canvas {
      min-width: 100%;
      min-height: 100%;
    }
  }

  &__mask {
    position: absolute;
    z-index: 99;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    padding-bottom: 5%;
    background-color: rgba($color: #ffffff, $alpha: 0.4);
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;

    &-icon {
      display: block;
      width: 64px;
      height: 64px;
      position: relative;

      i {
        position: absolute;
        top: 0;
        left: 0;
        width: 48px;
        height: 48px;
        border-radius: 50%;
        border: 8px solid rgba(66, 176, 235, 0.2);
        border-left-color: #42b0eb;
        animation: loading 1.1s infinite linear;
      }

      em {
        color: #42b0eb;
        font-size: 14px;
        line-height: 64px;
        font-style: normal;
      }
    }

    &-text {
      display: block;
      color: #333;
      font-size: 14px;
      padding-top: 12px;
    }
  }
}

@keyframes loading {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}
</style>
